home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / rclesrc.10 / ircle sources / ApplBase.pas next >
Encoding:
Pascal/Delphi Source File  |  1992-08-29  |  11.9 KB  |  512 lines

  1. {    ApplBase - Event dispatcher    }
  2. {    File:    ApplBase, version 2.0.2    }
  3. {    Copyright ⌐ 1991-1992 Olaf Titz (s_titz@iravcl.ira.uka.de)    }
  4.  
  5. {    This program is free software; you can redistribute it and/or modify    }
  6. {    it under the terms of the GNU General Public License as published by    }
  7. {    the Free Software Foundation; either version 2 of the License, or    }
  8. {    (at your option) any later version.    }
  9.  
  10. {    This program is distributed in the hope that it will be useful,    }
  11. {    but WITHOUT ANY WARRANTY; without even the implied warranty of    }
  12. {    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    }
  13. {    GNU General Public License for more details.    }
  14.  
  15. {    You should have received a copy of the GNU General Public License    }
  16. {    along with this program; if not, write to the Free Software    }
  17. {    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.    }
  18.  
  19. unit ApplBase;
  20.  
  21. interface
  22.  
  23. uses
  24.     Coroutines, 
  25.  
  26. {$IFC UseTCP}
  27.  
  28.     TCPTypes, TCPStuff, TCPConnections;
  29.  
  30. { If the compiler option UseTCP is set: }
  31. { This version cooperates with Peter Lewis' TCPConnections package. }
  32. { ConnectionEvents are treated just like regular events, having a priority }
  33. { dynamically changing from between key and update to lower. }
  34.  
  35. {$ENDC}
  36.  
  37. const
  38.     mouseMsg = 16;        { new 'events': mouseMsg+x, x=FindWindow result }
  39.     dialogMsg = 26;        { dialog: message=DialogPtr, item in theItem }
  40. {$IFC UseTCP}
  41.     TCPMsg = 27;        { Ptr to connectionEventRecord in message }
  42. {$ENDC}
  43.     menuMsg = -226;    { menuMsg+x, x=menu ID; menuBar=30 }
  44.  
  45.     menuBar = 256;        { res ID of MBAR }
  46.     appleMenu = 256;    { res ID of MENU: apple,file,edit }
  47.     FileMenu = 257;        { apple and edit menu are mandatory }
  48.     EditMenu = 258;
  49.  
  50. var
  51.     theItem: integer;                { item hit in dialog boxes }
  52.     RunningInCoroutine: boolean;    { if coroutine other than global active }
  53.     HighCoPriority: boolean;        { if Coroutines should run more often }
  54.     WNETime: integer;            { Timeout parameter for WaitNextEvent }
  55. {$IFC UseTCP}
  56.     maxTCPFlood: integer;        { max n of consecutive TCP events }
  57. {$ENDC}
  58.  
  59. { If you define the compile option TRACE to true, a file 'ApplBase Trace' }
  60. { will be generated on each run which records events, context switches etc. }
  61. { Refer to the source below for details. }
  62.  
  63. {$IFC TRACE}
  64.     trace: text;
  65. {$ENDC}
  66.  
  67. procedure ApplEvents (var e: EventRecord);
  68. { Process given event }
  69.  
  70. procedure ApplInit;
  71. { Init the package }
  72.  
  73. procedure ApplRun;
  74. { Get event and process it }
  75.  
  76. procedure ApplExitProc (p: ProcPtr);
  77. { install exitproc }
  78.  
  79. procedure ApplExit;
  80. { call exitprocs & exit program }
  81.  
  82. function ApplTask (mytask: ProcPtr; message: integer): integer;
  83. { Enqueue task }
  84.  
  85. procedure ApplUntask (n: integer);
  86. { Dequeue task }
  87.  
  88. {    Task declaration:   function mytask(var e:EventRecord):boolean    }
  89. {    should return true if event completely processed    }
  90. {    The following has been done on task entry: Current grafport saved,    }
  91. {    grafport set to whatever appropriate on events for windows (mouse,update,activ.)    }
  92. {    all processing of DAs (SystemEdit...) and dialog events    }
  93.  
  94. function ApplCoroutine (mytask: ProcPtr; wspsize: integer): integer;
  95. { Start Coroutine in background, i.e. on null events }
  96.  
  97. function ApplWaitPB (pb: ParmBlkPtr): integer;
  98. { Wait for completion of async FileMgr call in background }
  99.  
  100.  
  101. implementation
  102.  
  103. const
  104.     NMSGS = 40;         { this means max. 10 menus }
  105.  
  106. type
  107.     EvtQuPtr = ^EvtQuRec;    { Event handler queue }
  108.     EvtQuRec = record
  109.             qLink: EvtQuPtr;
  110.             taskID: integer;
  111.             eProc: ProcPtr
  112.         end;
  113.  
  114.     BkQuPtr = ^BkQuRec;        { Background procs queue }
  115.     BkQuRec = record
  116.             qLink: BkQuPtr;
  117.             WSP: handle
  118.         end;
  119.  
  120.     ExQuPtr = ^ExQuRec;        {╩Exitproc queue }
  121.     ExQuRec = record
  122.             qLink: ExQuPtr;
  123.             eProc: ProcPtr
  124.         end;
  125.  
  126. var
  127.     EvtQuHdr: array[0..NMSGS] of EvtQuPtr;
  128.     EvtTID: integer;
  129.     ThisBack, LastBack: BkQuPtr;
  130.     ExitQuHdr: ExQuPtr;
  131.     applMItems: integer;
  132.     WindowDragRect: Rect;
  133.     univRgn: RgnHandle;
  134. {$IFC UseTCP}
  135.     TCPFlood: integer;
  136. {$ENDC}
  137.  
  138. function ECALL (var e: EventRecord; p: ProcPtr): boolean;
  139. inline
  140.     $205F, $4E90;        { movea.l (a7)+,a0; jsr (a0) }
  141.  
  142.  
  143. procedure ApplEvents (var e: EventRecord);
  144.     var
  145.         i: integer;
  146.         p, p0: WindowPtr;
  147.         l: EvtQuPtr;
  148.     begin
  149.         GetPort(p0);
  150.         if (e.what = keyDown) and (BitAnd(e.modifiers, cmdKey) <> 0) then begin
  151.             e.message := MenuKey(chr(e.message mod 256));  { Menu shortcut.. }
  152.             e.what := menuMsg
  153.         end
  154.         else if (e.what >= 0) and (e.what <= 15) then
  155.             if IsDialogEvent(e) then begin
  156. {$IFC TRACE}
  157.                 write(trace, 'D');
  158. {$ENDC}
  159.                 if (e.what = keyDown) and ((BitAnd(loword(e.message), 255) = 3) or (BitAnd(loword(e.message), 255) = 13)) then begin
  160.                     e.what := dialogMsg;    { Pressing Return or Enter in dialog... }
  161.                     e.message := longint(FrontWindow);
  162.                     theItem := 0            { is reported as Item #0 }
  163.                 end
  164.                 else if DialogSelect(e, p, theItem) then begin
  165.                     e.what := dialogMsg;        { Let the Dialog Mgr process the event... }
  166.                     e.message := longint(p)        { and report which dialog and item }
  167.                 end
  168.                 else if e.what <> 0 then
  169.                     exit(ApplEvents);            { DialogSelect has completely processed }
  170.             end;
  171.         if e.what = mouseDown then begin
  172.             i := FindWindow(e.where, p);
  173.             case i of
  174.                 inSysWindow: 
  175.                     begin
  176.                     if p = FrontWindow then
  177.                         SystemClick(e, p)
  178.                     else
  179.                         SelectWindow(p);
  180.                     exit(ApplEvents)
  181.                 end;
  182.                 inMenuBar: 
  183.                     begin
  184.                     e.message := MenuSelect(e.where);
  185.                     e.what := menuMsg
  186.                 end;
  187.                 otherwise
  188.                     if ((i = inContent) or (i = inGrow)) and (p <> FrontWindow) then begin
  189.                         SelectWindow(p);    { if click in non-active window, select it.. }
  190.                         exit(ApplEvents)
  191.                     end
  192.                     else begin
  193.                         SetPort(p);    { the window where the click is in }
  194.                         e.what := mouseMsg + i;
  195.                         e.message := longint(p)
  196.                     end
  197.             end;
  198.         end;
  199.         if e.what = menuMsg then begin    { Split the menu message }
  200. {$IFC TRACE}
  201.             write(trace, 'M');
  202. {$ENDC}
  203.             if HiWord(e.message) = 0 then
  204.                 e.what := 0
  205.             else begin
  206.                 e.what := menuMsg + HiWord(e.message);    { menuMsg+menuNo }
  207.                 e.message := LoWord(e.message);            { itemNo }
  208.                 if e.what = menuMsg + EditMenu then
  209.                     if SystemEdit(e.message - 1) then        { handle edit in DA }
  210.                         exit(ApplEvents)
  211.             end
  212.         end;
  213.         if (e.what = updateEvt) or (e.what = activateEvt) then
  214.             SetPort(WindowPtr(e.message));
  215.         l := EvtQuHdr[e.what];
  216.         while l <> nil do
  217.             with l^ do begin    { Call tasks }
  218.                 if ECALL(e, eProc) then
  219.                     leave;
  220.                 l := qLink
  221.             end;
  222.         HiliteMenu(0);
  223.         SetPort(p0);
  224.     end;
  225.  
  226.  
  227.  
  228. { --- Standard tasks --- }
  229.  
  230. function Accessories (var e: EventRecord): boolean; { menuMsg+appleMenu }
  231.     var
  232.         s: str255;
  233.         i: integer;
  234.     begin
  235.         if e.message > applMItems then begin                            { DA item selected? }
  236.             GetItem(GetMHandle(appleMenu), LoWord(e.message), s);    { Open it }
  237.             i := OpenDeskAcc(s);
  238.         end;
  239.         Accessories := true;
  240.     end;
  241.  
  242.  
  243. function AccessoryActivate (var e: EventRecord): boolean; {activateEvt }
  244.     var
  245.         p: WindowPeek;
  246.         m: MenuHandle;
  247.         i: integer;
  248.     begin
  249.         p := WindowPeek(e.message);
  250.         if p^.windowKind < 0 then begin    { DA window selected? }
  251.             if BitAnd(e.modifiers, activeFlag) <> 0 then begin
  252.                 m := GetMHandle(EditMenu);    { Yes -> enable Edit menu and }
  253.                 for i := 0 to 6 do                { standard Edit options }
  254.                     EnableItem(m, i);
  255.                 DisableItem(m, 2);                { but not the separator }
  256.             end
  257.             else
  258.                 InitCursor;                    { DA window deselected? -> reset the mouse cursor }
  259.         end;
  260.         AccessoryActivate := true;
  261.     end;
  262.  
  263.  
  264. function WindowDragging (var e: EventRecord): boolean;
  265.     begin
  266.         DragWindow(WindowPtr(e.message), e.where, WindowDragRect);
  267.         WindowDragging := true;
  268.     end;
  269.  
  270.  
  271. function CancelUpdates (var e: EventRecord): boolean;
  272.     begin
  273.         BeginUpdate(WindowPtr(e.message));    { Purge update events that have not been processed }
  274.         EndUpdate(WindowPtr(e.message));
  275.         CancelUpdates := true
  276.     end;
  277.  
  278. function BackgroundRun (var e: EventRecord): boolean;
  279.     begin
  280.         if ThisBack <> nil then begin
  281.             RunningInCoroutine := true;
  282.             Transfer(GlobalProc, ThisBack^.WSP);
  283.             RunningInCoroutine := false;
  284.             if GetHandleSize(ThisBack^.WSP) <= 0 then
  285.                 if LastBack = ThisBack then begin
  286.                     LastBack := nil;
  287.                     dispose(ThisBack);
  288.                     ThisBack := nil
  289.                 end
  290.                 else begin
  291.                     LastBack^.qLink := ThisBack^.qLink;
  292.                     dispose(ThisBack);
  293.                     ThisBack := LastBack^.qLink
  294.                 end
  295.             else begin
  296.                 LastBack := ThisBack;
  297.                 ThisBack := ThisBack^.qLink
  298.             end
  299.         end;
  300. {$IFC TRACE}
  301.         write(trace, 'B');
  302. {$ENDC}
  303.         BackgroundRun := true
  304.     end;
  305.  
  306.  
  307. function ApplTask (mytask: ProcPtr; message: integer): integer;
  308.     var
  309.         p: EvtQuPtr;
  310.     begin
  311.         EvtTID := EvtTID + 1;
  312.         new(p);
  313.         if p = nil then begin
  314. {$IFC TRACE}
  315.             write(trace, 'Failed ');
  316. {$ENDC}
  317.             ApplTask := -1
  318.         end
  319.         else
  320.             with p^ do begin
  321.                 ApplTask := EvtTID;
  322.                 qLink := EvtQuHdr[message];
  323.                 taskID := EvtTID;
  324.                 eProc := mytask;
  325.                 EvtQuHdr[message] := p;
  326.             end;
  327. {$IFC TRACE}
  328.         writeln(trace, 'ApplTask: ', mytask, message, EvtTID);
  329. {$ENDC}
  330.     end;
  331.  
  332.  
  333.  
  334. procedure ApplUntask (n: integer);
  335.     var
  336.         p, p0: EvtQuPtr;
  337.         i: integer;
  338.     begin
  339. {$IFC TRACE}
  340.         writeln(trace, 'ApplUntask ', n);
  341. {$ENDC}
  342.         for i := 0 to NMSGS do begin
  343.             p := EvtQuHdr[i];
  344.             if p <> nil then begin
  345.                 if p^.taskID = n then begin
  346.                     EvtQuHdr[i] := p^.qLink;
  347.                     exit(ApplUntask)
  348.                 end
  349.                 else
  350.                     repeat
  351.                         p0 := p;
  352.                         p := p0^.qLink;
  353.                         if p = nil then
  354.                             leave;
  355.                         if p^.taskID = n then begin
  356.                             p0^.qLink := p^.qLink;
  357.                             dispose(p);
  358.                             exit(ApplUntask)
  359.                         end;
  360.                     until false;
  361.             end
  362.         end;
  363.     end;
  364.  
  365.  
  366.  
  367. function ApplCoroutine (mytask: ProcPtr; wspsize: integer): integer;
  368.     var
  369.         h: Handle;
  370.         p: BkQuPtr;
  371.     begin
  372.         h := Newprocess(mytask, wspsize);
  373.         ApplCoroutine := MemError;
  374. {$IFC TRACE}
  375.         writeln(trace, 'ApplCoroutine ', mytask, wspsize, MemError);
  376. {$ENDC}
  377.         if h <> nil then begin
  378.             New(p);
  379.             if p = nil then begin
  380.                 DisposHandle(h);
  381.                 ApplCoroutine := MemError
  382.             end
  383.             else begin
  384.                 if LastBack <> nil then
  385.                     LastBack^.qLink := p;
  386.                 LastBack := p;
  387.                 if ThisBack = nil then
  388.                     ThisBack := p;
  389.                 p^.qLink := ThisBack;
  390.                 p^.WSP := h;
  391.             end
  392.         end
  393.     end;
  394.  
  395.  
  396.  
  397.  
  398. procedure ApplInit;
  399.     var
  400.         m: MenuHandle;
  401.         h: Handle;
  402.         p: GrafPtr;
  403.         i: integer;
  404.     begin
  405. {$IFC TRACE}
  406.         rewrite(trace, 'ApplBase Trace');
  407. {$ENDC}
  408.         for i := 0 to NMSGS do
  409.             EvtQuHdr[i] := nil;
  410.         ThisBack := nil;
  411.         LastBack := nil;
  412.         ExitQuHdr := nil;
  413.         RunningInCoroutine := false;
  414.         HighCoPriority := false;
  415.         WNETime := 10;
  416.         EvtTID := 0;
  417. {$IFC UseTCP}
  418.         TCPFlood := 0;
  419.         maxTCPFlood := 5;
  420. {$ENDC}
  421.         GetWMgrPort(p);
  422.         WindowDragRect := p^.portRect;
  423.         WindowDragRect.top := WindowDragRect.top + 20;
  424.         InsetRect(WindowDragRect, 4, 4);
  425.         univRgn := NewRgn;
  426.         SetRectRgn(univRgn, -32767, -32767, 32767, 32767);
  427.         h := GetNewMBar(menuBar);
  428.         SetMenuBar(h);
  429.         DrawMenuBar;
  430.         m := GetMHandle(appleMenu);
  431.         applMItems := CountMItems(m);
  432.         AddResMenu(m, 'DRVR');
  433.         i := ApplTask(@BackgroundRun, nullEvent);
  434.         i := ApplTask(@CancelUpdates, updateEvt);
  435.         i := ApplTask(@Accessories, menuMsg + appleMenu);
  436.         i := ApplTask(@AccessoryActivate, activateEvt);
  437.         i := ApplTask(@WindowDragging, mouseMsg + inDrag);
  438.         FlushEvents(everyEvent, 0);
  439.     end;
  440.  
  441.  
  442. procedure ApplRun;
  443.     var
  444.         e: EventRecord;
  445.         connEvt: ConnectionEventRecord;
  446.         b: Boolean;
  447.     begin
  448.         if RunningInCoroutine then begin
  449. {$IFC TRACE}
  450.             write(trace, 'G');
  451. {$ENDC}
  452.             Transfer(ThisBack^.WSP, GlobalProc)
  453.         end
  454.         else begin
  455. {$IFC TRACE}
  456.             write(trace, 'W');
  457. {$ENDC}
  458.             b := WaitNextEvent(-1, e, WNETime, univRgn);
  459. {$IFC UseTCP}
  460.             if (e.what = nullEvent) or (e.what = updateEvt) then
  461.                 if TCPFlood < maxTCPFlood then
  462.                     if GetConnectionEvent(any_connection, connEvt) then begin
  463. {$IFC TRACE}
  464.                         write(trace, 'C', ord(connEvt.event) : 2);
  465. {$ENDC}
  466.                         e.what := TCPMsg;
  467.                         e.message := longint(@ConnEvt);
  468.                         TCPFlood := TCPFlood + 1
  469.                     end
  470.                     else
  471.                         TCPFlood := 0
  472.                 else
  473.                     TCPFlood := 0;
  474. {$ENDC UseTCP}
  475.             ApplEvents(e);
  476.             if HighCoPriority then
  477.                 b := BackgroundRun(e);
  478.         end;
  479.     end;
  480.  
  481.  
  482. procedure ApplExitProc (p: ProcPtr);
  483.     var
  484.         e: ExQuPtr;
  485.     begin
  486.         new(e);
  487.         e^.qLink := ExitQuHdr;
  488.         e^.eProc := p;
  489.         ExitQuHdr := e;
  490.     end;
  491.  
  492. procedure CALL (p: ProcPtr);
  493. inline
  494.     $205F, $4E90;        { movea.l (a7)+,a0; jsr (a0) }
  495.  
  496. procedure ApplExit;
  497.     var
  498.         ep: ExQuPtr;
  499.     begin
  500.         ExitCoroutines;
  501.         ep := ExitQuHdr;
  502.         while ep <> nil do begin
  503.             CALL(ep^.eProc);
  504.             ep := ep^.qLink
  505.         end;
  506. {$IFC TRACE}
  507.         close(trace);
  508. {$ENDC}
  509.         halt;
  510.     end;
  511.  
  512. end.